#include "StdAfx.h"
#include "TestTree.h"
#include "DteFunctions.h"
#include "SourceCodeHandler.h"

TestProject::TestProject(void)
{
}

TestProject::~TestProject(void)
{
}

BOOL TestProject::Prepare(const EnvDTE::ProjectPtr & spProject)
{
	BOOL bRet = FALSE;
	m_aGroups.RemoveAll();

	if ((spProject) &&
		RecursiveElementEnumeration(spProject, this))
	{
		bRet = TRUE;
	}

	return bRet;
}

BOOL TestProject::Element(EnvDTE::CodeElement * pElement)
{
	static CComBSTR bstrGetTestFuncs(L"GetTestsFunc");

	EnvDTE::CodeElementPtr spElement(pElement);

	if (IsElementTestGroup(spElement))
	{
		EnvDTE::CodeElementsPtr spElements;
		//a test group could be either class or struct
		VCCodeModelLibrary::VCCodeClassPtr spClass;
		VCCodeModelLibrary::VCCodeStructPtr spStruct;
		VCCodeModelLibrary::VCCodeElementsPtr spVcElements;
		
		if (spClass = spElement) 
			spClass->get_Functions(&spElements);
		else if (spStruct = spElement)
			spStruct->get_Functions(&spElements);

		CComBSTR bstrBody;
		IDispatchPtr spDispatch;
		VCCodeModelLibrary::VCCodeFunctionPtr spGetTestsFunc;
		//VCCodeModelLibrary::VCCodeFunction::get_BodyText does not work so a function body retrieved by start and end points
		EnvDTE::TextPointPtr spStart, spEnd;
		EnvDTE::EditPointPtr spEditPoint;
		
		if ((spVcElements = spElements) &&
			SUCCEEDED(spVcElements->Find(bstrGetTestFuncs, &spDispatch)) &&
			(spGetTestsFunc = spDispatch) &&
			SUCCEEDED(spGetTestsFunc->get_StartPoint(&spStart)) &&
			SUCCEEDED(spGetTestsFunc->get_EndPoint(&spEnd)) &&
			SUCCEEDED(spStart->CreateEditPoint(&spEditPoint)) &&
			SUCCEEDED(spEditPoint->GetText(CComVariant((LPDISPATCH)spEnd), &bstrBody)))
		{
			ParseGetTestsFunc(bstrBody);		
		}
	}
	return TRUE;
}

void TestProject::ParseGetTestsFunc(LPCWSTR lpBody)
{
	CAtlStringW wstr = lpBody;
	ReplaceCommentAndTextLiteral(wstr, wstr);
	
	int nFind = FindLexeme(wstr, L"BEGIN_UT_FUNC_TABLE");
	int nEnd = FindLexeme(wstr, L"END_UT_FUNC_TABLE");
	if ((-1 == nFind) || (-1 == nEnd) || (nFind > nEnd))
		return;
	wstr = wstr.Left(nEnd);

	nFind += _countof(L"BEGIN_UT_FUNC_TABLE") - 1; //-1 to ignore '\0' in the literal constant
	int nOpenBrace = wstr.Find(L'(', nFind);
	int nCloseBrace = wstr.Find(L')', nFind);
	if (nOpenBrace > nCloseBrace)
		return;

	TestGroupRun & rGroup = m_aGroups.GetAt(m_aGroups.Add());
	++nOpenBrace; //remove L'(' as factor
	rGroup.wstrName = wstr.Mid(nOpenBrace, nCloseBrace - nOpenBrace).Trim();

	while (-1 != (nFind = FindLexeme(wstr, L"UT_FUNC_ENTRY", nFind)))
	{
		nFind += _countof(L"UT_FUNC_ENTRY") - 1; //-1 to ignore '\0' in the literal constant
		nOpenBrace = wstr.Find(L'(', nFind);
		nCloseBrace = wstr.Find(L')', nFind);
		if (nOpenBrace > nCloseBrace)
		{
			break;
		} else {
			nFind = nCloseBrace + 1;
		}

		++nOpenBrace; //remove L'(' as factor
		TestRun & rTestRun = rGroup.aTests.GetAt(rGroup.aTests.Add());
		rTestRun.wstrName = wstr.Mid(nOpenBrace, nCloseBrace - nOpenBrace).Trim();
	}
}